package gbench.common.matlib.data;

import static gbench.common.matlib.data.Pipe.DUMMY;
import static gbench.common.tree.LittleTree.IRecord.llclc;
import static gbench.common.tree.LittleTree.kvp_int;
import static gbench.common.tree.LittleTree.IRecord.REC;

import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import gbench.common.fs.FileSystem;
import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.MatlibCanvas.Range;
import gbench.common.matlib.MatlibCanvas.TVec;
import gbench.common.matlib.MatlibCanvas.Weightable;
import gbench.common.matlib.MatlibCanvas.XVec;
import gbench.common.matlib.rdd.BasePair;
import gbench.common.matlib.rdd.PVec;
import gbench.common.tree.LittleTree;
import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.KVPair;
import gbench.common.tree.LittleTree.Tuple2;

/**
 * 文本数据读取&变换器
 * @author gbench
 *
 */
public class DataReader {
    
    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @param dfname 数据框的名称
     * @return dfname 所指定的DFrame
     */
    public static DFrame loaddf(final String datafile,String dfname) {
        return loaddfs(datafile,DELIM).get(dfname);
    }

    /**
     * 从数据文件里面提取数据
     * @param datafile 源文件名称
     * @param dfname 数据框的名称
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static DFrame loaddf(final File datafile,String dfname) {
       return loaddfs(datafile,DELIM).get(dfname);
    }

    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static Map<String,DFrame> loaddfs(final String datafile) {
        return loaddfs(new File(datafile),DELIM);
    }
    
    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @param delim 数据间的 数据单元的分隔符的模式
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static Map<String,DFrame> loaddfs(final String datafile,final String delim) {
        return loaddfs(new File(datafile),delim);
    }
    
    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static Map<String,DFrame> loaddfs(final File datafile) {
        return loaddfs(datafile,DELIM);
    }
    
    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @param delim 数据间的 数据单元的分隔符的模式
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static Map<String,DFrame> loaddfs(final File datafile,final String delim) {
        return load(datafile,delim).aovs(DFrame::DF);
    }

    /**
     * 从数据文件里面提取数据
     * @param datafile 文件的绝对路径，比如: "C:/Users/gbench/Desktop/data.txt"
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static IRecord load(final String datafile) {
        return load(new File(datafile));
    }

    /**
     * 从数据文件里面提取数据
     * @param datafile 源文件名称
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static IRecord load(final File datafile) {
        
        return load(datafile,DELIM);
    }
    
    /**
     * 从数据文件里面提取数据
     * @param datafile 源文件名称
     * @param delim 数据间的 数据单元的分隔符的模式
     * @return {数据框名,rec结构的数据（框）},数据（框） 是一个带有名称的列向量集合,列结构为:(列名->[列数据元素])
     */
    public static IRecord load(final File datafile,final String delim) {
        
        final var tables = REC();// 数据（框）集合
        final var dataTables = getDataLines(datafile);// 读成 {数据框名->[line]}的rec结构。
        final Predicate<List<String>> is_long_format = (ll)->ll.get(0).strip().startsWith("|"); // 是否长结构表，长表结构的首行为表头 以|开头。
        
        dataTables.foreach((dfname, data) -> {
            @SuppressWarnings("unchecked")
            final var dataLines = (List<String>)data;
            if(dataLines.size()<1) {
                System.err.println("表"+dfname+"没有数据！");
                return;
            }
            final var table = is_long_format.test(dataLines)?read_long_format(dataLines,delim):read_width_format(dataLines,delim);
            tables.add(dfname,table);
        });// foreach 数据遍历
        
        return tables;
    }
    
    /**
     * "-- #" 为注释 <br>
     * "-- table 为表名 <br>
     * | 开头引导 长格式的 数据列 <br>
     * xx | 开头引导 宽格式的 数据 行<br>
     * 从源文件读取所有的数据（框），一个datafile可以保存有多个数据（框）。<br>
     * 一份数据文件可以是如下的格式: <br>
     * <br>
     * ------------------------------------------------- <br>
     * -- #数据表1,长格式 <br>
     * -- table1 <br>
     * ------------------------------------------------- <br>
     * | x  y   sigma [表头的定义]<br>
     * 4.41 0.43    0.08 <br>
     * 4.60 0.99    0.15 <br>
     * 4.95 0.87    0.22 <br>
     * 5.28 2.09    0.32 <br>
     * ------------------------------------------------- <br>
     * -- #表6-3 宽格式
     * -- table3 <br>
     * ------------------------------------------------- <br>
     * x(身高)   |   155 157 157 159 161 163 163 165 167 <br>
     * y(体重)   |   42  47  44  47  50  49  53  52  55  <br>
     * 
     * @param datafile 数据文件 由一系列的 长/宽 表框 的数据构成。<br>
     * 不同表之间采用 -- 表名 , -- # (注意#前有个空格) 注释，进行分隔 <br>
     * @return IRecord {数据框名,该数据框下的所有行DataLines的LIST}
     */
    public static IRecord getDataLines(final File datafile) {
        
        final var dataTables = REC(); // 数据（框）
        final var ar_table_name = new AtomicReference<String>();
        final var ar_table_body = new AtomicReference<LinkedList<String>>();
        final var pattern = Pattern.compile("^--\\s+(.*)$"); // 表头行
        final Consumer<String> data_table_builder = (name)->{//把 header 和 body 添加到  结果集合之中
            final var tblname = name==null?ar_table_name.get():ar_table_name.getAndSet(name); // 数据（框）名
            final var body = ar_table_body.getAndSet(new LinkedList<>());// 数据（框）体
            if (tblname != null && body != null)  dataTables.add(tblname,body);
        };// 数据（框）构建器
        
        FileSystem.utf8lines(datafile)// 读取数据文件
        .filter(line->!line.matches("(^\\s*$)|(^[-\\s]*$)|(^-- #.*$)")) // -- #被视作注释
        .forEach(line->{
            final var matcher = pattern.matcher(line);
            if (matcher.matches()) {
                data_table_builder.accept(matcher.group(1));
                return;
            } else {
                ar_table_body.updateAndGet(u->{
                    (u==null? new LinkedList<String>(): u).add(line);
                    return u;
                });
            }// if
        });//forEach
        
        data_table_builder.accept(null);
        
        return dataTables;
    }
    
    /**
     * 从源文件里面读取数据
     * @param dataLines 数据（框）行：宽结构
     * @return 命名列向量结构的 KVP集合IRecord
     */
    public static IRecord read_width_format(final List<String> dataLines) {
        
        return read_width_format(dataLines,DELIM);
    }

    /**
     * 从源文件里面读取数据
     * @param dataLines 数据（框）行：宽结构
     * @param delim 数据间的 数据单元的分隔符的模式
     * @return 命名列向量结构的 KVP集合IRecord
     */
    public static IRecord read_width_format(final List<String> dataLines,final String delim) {
        
        final var rec = REC();
        final var pattern = Pattern.compile("(([^|]+)\\|)?(.*)$");
        dataLines.stream().filter(line->!line.matches("(^\\s*$)|(^--\\s+.*$)"))
        .forEach(line->{
            final var matcher = pattern.matcher(line);
            if(matcher.matches()) {
                final var name = matcher.group(2).trim();
                final var data = matcher.group(3).trim();
                rec.add(name,data.split(delim));
            }//if
        });//forEach
        
        return rec;
    }
    
    /**
     * 从源文件里面读取数据
     * @param dataLines 数据（框）行:长结构
     * @return 命名列向量结构的 KVP集合IRecord
     */
    public static IRecord read_long_format(final List<String> dataLines) {
        return read_long_format(dataLines,DELIM);
    }
    
    /**
     * 从源文件里面读取数据
     * @param dataLines 数据（框）行:长结构
     * @param delim 数据间的 数据单元的分隔符的模式
     * @return 命名列向量结构的 KVP集合IRecord
     */
    public static IRecord read_long_format(final List<String> dataLines,final String delim) {
        
        final var rec = REC();
        final var headerline = dataLines.get(0).strip().substring(1).strip(); // 提取表头
        Arrays.stream(headerline.split(delim)).map(String::strip).forEach(h -> rec.add(h, new LinkedList<String>())); // 初始化column列向量
        final var size = rec.size();
        
        (dataLines.subList(1, dataLines.size())).stream() // 除掉第一行：表头
        .filter(line->!line.matches("(^\\s*$)|(^--\\s+.*$)")) // 剔除空行, 注释行
        .forEach(line -> Arrays.stream(line.split(delim)).map(kvp_int()) // 行元素分解，并进行数据编号
            .forEach(tup -> rec.get(tup._1()%size, (List<String> vv)->{
                vv.add(tup._2()); // 添加向量元素
                return vv;
            })));//forEach
        
        return rec;
    }
    
    /**
     * 绘图变换器
     * @param rng 绘图空间 象素坐标
     * @param values 业务数据空间（业务数据值)，需要包含最大，最小值
     * @return 绘制变换器:数据空间数值x->绘图的象素坐标, 业务数据空间 的值 所对应的 绘图空间 中的象素坐标。
     */
    public static Function<Double,Double> transformer(final Range rng,final List<Double> values){
        
        final var stats = values.stream().collect(Collectors.summarizingDouble(e->e));//数据空间的统计
        final var max = stats.getMax();
        final var min = stats.getMin();
        final var len = max-min;// 数据空间的区间大小
        final var ratio = Math.abs((rng.end()-rng.start()))/len; // 单位数量空间所占据的绘图空间。
        
        return x->(x-min)*ratio+rng.start();
    }
    
    /**
     * 绘图变换器
     * @param rng 绘图空间 象素坐标
     * @param values 业务数据空间（业务数据值),需要包含最大，最小值
     * @return 绘制变换器:绘图空间坐标x->业务数据空间数值,绘图空间中的位置坐标,位于 业务数据空间中的值 的大小
     */
    public static Function<Double,Double> detransformer(final Range rng,final List<Double> values){
        
        final var stats = values.stream().collect(Collectors.summarizingDouble(e->e)); // 数据空间统计
        final var max = stats.getMax();
        final var min = stats.getMin();
        final var len = max-min;// 数据空间的区间大小
        final var ratio = Math.abs((rng.end()-rng.start()))/len; // 单位数量空间所占据的绘图空间。
        
        return c->(c-rng.start())/ratio+min;
    }
    
    /**
     * 数据框对象：
     * 一个数据框就一个按照列进行存储的数据集合。
     * 数据框默认处理浮点类型的数据。<br>
     * @author gbench
     *
     */
    public static class DFrame{
        
        /**
         * 构造函数
         * @param data DataFrame 结构的数据结构，每个value都是一个List<String>
         * @param b 是否调整data数据,true调整,false 不调整
         */
        public DFrame(final IRecord data, final boolean b) {
            this.data = !b?data:DFrame.adjustData(data, (Object[])null);
        }
        
        /**
         * 构造函数:（不调整数据)
         * @param data DataFrame 结构的数据结构，每个value都是一个List<String>
         */
        public DFrame(final IRecord data) {
            this(data, false);
        }
        
        /**
         * 构造函数:（不调整数据)
         * @param kvs oo 键,值序列:key0,value0,key1,value1,....
         */
        public DFrame(final Object ... kvs) {
            this(REC(kvs), false);
        }
        
        /**
         * 数值化对象:请使用值保证 name为字符串列表或是数组类型的数值数据，
         * @param name 数据列的列名
         * @return NVec
         */
        public NVec get(final String name) {
            return data.get(name,numerialize);
        }
        
        /**
         * 提取name列的数据
         * @param <U> 元素类型
         * @param name 数据列的列名
         * @param u 元素类型/默认值占位符
         * @return 元素类型为T类型的XVec
         */
        public <U> XVec<U> get(final String name,final U u) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(u))));
        }
        
        /**
         * 数值化对象:请使用值保证 idx为List<String>类型数值数据，
         * @param idx 数据列的序号 从0开始
         * @return NVec
         */
        public NVec get(final Number idx) {
            return data.get(idx.intValue(),numerialize);
        }

        /**
         * 提取idx列的数据
         * @param <U> 元素类型
         * @param idx 数据列的序号 从0开始
         * @param u 元素类型/默认值占位符
         * @return 元素类型为T类型的XVec
         */
        public <U> XVec<U> get(final int idx,final U u) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(u))));
        }

        /**
         * 提取name列的数据
         * @param <T> 源数据类型
         * @param <U> 目标数据类型
         * @param name 数据列的列名
         * @param mapper 数据变换函数 :t->u
         * @return U
         */
        public <T,U> U get(final String name,final Function<T,U> mapper) {
            return data.get(name,mapper);
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为String类型的XVec
         */
        public XVec<String> str(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, e->e+"")));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为String类型的XVec
         */
        public XVec<String> str(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, e->e+"")));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为Boolean类型的XVec,元素默认值为false
         */
        public XVec<Boolean> bool(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(false))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为Boolean类型的XVec,元素默认值为false
         */
        public XVec<Boolean> bool(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(false))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为Boolean类型的XVec,元素默认值为'-'
         */
        public XVec<Character> chr(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, o->{
                if(o instanceof Number)return (char)((Number)o).intValue();
                else if(o instanceof String && ((String)o).length()>0)return (char)((String)o).charAt(0);
                else if(o instanceof Character)return ((Character)o);
                else return '-';
            })));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为Character类型的XVec,元素默认值为'-'
         */
        public XVec<Character> chr(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u('-'))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为Integer类型的XVec,元素默认值为0
         */
        public XVec<Integer> i4(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(0))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为Integer类型的XVec,元素默认值为0
         */
        public XVec<Integer> i4(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(0))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为Long类型的XVec,元素默认值为0
         */
        public XVec<Long> lng(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(0L))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为Long类型的XVec,元素默认值为0
         */
        public XVec<Long> lng(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(0L))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为Long类型的XVec,元素默认值为0
         */
        public XVec<Double> dbl(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(0d))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为Double类型的XVec,元素默认值为0
         */
        public XVec<Double> dbl(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(0d))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为LocalDateTime类型的XVec,元素默认值为now
         */
        public XVec<LocalDateTime> ldt(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(LocalDateTime.now()))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为LocalDateTime类型的XVec,元素默认值为now
         */
        public XVec<LocalDateTime> ldt(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(LocalDateTime.now()))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为LocalDateTime类型的XVec,元素默认值为now
         */
        public XVec<LocalDate> ld(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(LocalDate.now()))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为LocalDateTime类型的XVec,元素默认值为now
         */
        public XVec<LocalDate> ld(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(LocalDate.now()))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为LocalTime类型的XVec,元素默认值为now
         */
        public XVec<LocalTime> lt(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(LocalTime.now()))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为LocalTime类型的XVec,元素默认值为now
         */
        public XVec<LocalTime> lt(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(LocalTime.now()))));
        }

        /**
         * 提取name列的数据
         * @param name 数据列的列名
         * @return 元素类型为LocalTime类型的XVec,元素默认值为now
         */
        public XVec<Date> date(final String name) {
            return this.eval(rec->XVec.OF(rec.lla(name, t2u(new Date()))));
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的列名索引，从0开始
         * @return 元素类型为LocalTime类型的XVec,元素默认值为now
         */
        public XVec<Date> date(final int idx) {
            return this.eval(rec->XVec.OF(rec.lla(idx, t2u(new Date()))));
        }

        /**
         * 数值化对象:请使用值保证 name为字符串列表或是数组类型的数值数据，
         * @param name 数据列的列名
         * @return FVec &lt;String&gt;
         */
        public FVec<Object> fget(final String name) {
            return data.get(name,factorize);
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的序号 从0开始
         * @return Double数组
         */
        public Double[] fget2(final Number idx) {
            return this.fget(idx).data();
        }

        /**
         * 数值化对象:请使用值保证 name为字符串列表或是数组类型的数值数据，
         * @param name 数据列的列名
         * @return Double数组
         */
        public Double[] fget2(final String name) {
            return this.fget(name).data();
        }
        
        /**
         * 提取idx列的数据
         * @param idx 数据列的序号 从0开始
         * @return FVec &lt;String&gt;
         */
        public FVec<Object> fget(final Number idx) {
            return data.get(idx.intValue(),factorize);
        }
        
        /**
         * 提取idx列的数据
         * @param <T> 源数据类型
         * @param <U> 管道结果数据类型
         * @param idx 数据列的序号 从0开始
         * @param mapper 数据变换函数:t->u
         * @return U
         */
        public <T,U> U get(final Number idx,final Function<T,U> mapper) {
            return data.get(idx.intValue(),mapper);
        }
        
        /**
         * 管道计算<br>
         * 提取name列的数据
         * 
         * @param <T>  源数据类型
         * @param <U>  管道结果数据类型
         * @param name 数据列的列名
         * @param pipe 数据计算管道:[t->u]
         * @return U
         */
        @SuppressWarnings("unchecked")
        public <T, U> U pipe(final String name, final Pipe<T, U> pipe) {
            return data.get(name, t -> pipe.evaluate((T) t));
        }

        /**
         * 管道计算<br>
         * 提取idx列的数据
         * 
         * @param <T>  源数据类型
         * @param <U>  管道结果数据类型
         * @param idx  数据列的序号 从0开始
         * @param pipe 数据计算管道:[t->u]
         * @return U
         */
        @SuppressWarnings("unchecked")
        public <T, U> U pipe(final Number idx, final Pipe<T, U> pipe) {
            return data.get(idx.intValue(), t -> pipe.evaluate((T) t));
        }
        
        /**
         * 转换成XVec列表
         * 
         * @param <T>    T 目标结果类型
         * @param mapper 目标转换函数:obj->t
         * @return 转换成XVec列表
         */
        public <T> XVec<XVec<T>> toXVec(final Function<Object, T> mapper) {
            return this.data.stream().map(LittleTree.Tuple2::_2)
                    .map(e -> obj2stream(e).map(mapper).collect(IRecord.aaclc(XVec::OF))).collect(IRecord.aaclc(XVec::OF));
        }
        
        /**
         * 转换成XVec列表
         * 
         * @param <T>    T 目标结果类型
         * @param clazz 类型占位符
         * @return 转换成XVec列表，每个元素类型都是 T类型向量XVec
         */
        public <T> XVec<XVec<T>> toXVec(final Class<T> clazz){
            return this.toXVec(Pipe.CAST(clazz));
        }
        
        /**
         * 转换成XVec列表
         * @return 转换成XVec列表
         */
        public XVec<XVec<Object>> toXVec() {
            return this.toXVec(e->e);
        }
        
        /**
         * 转换成XVec列表
         * @return 转换成XVec列表
         */
        public XVec<FVec<Object>> toXVecf() {
            return this.data.stream().map(LittleTree.Tuple2::_2).map(factorize).collect(IRecord.aaclc(XVec::OF));
        }
        
        /**
         * 转换成XVec列表
         * 
         * @return 转换成XVec列表，每个元素类型都是 Double类型向量XVec
         */
        public XVec<XVec<Double>> dblXVec(){
            return this.toXVec(Pipe.CAST(Double.class));
        }
        
        /**
         * 转换成数据矩阵
         * @return 转换成数据矩阵
         */
        public Double[][] toArray(){
            return this.toArray(Double.class);
        }
        
        /**
         * 转换成数据矩阵
         * @param <T> 矩阵元素的类型
         * @param clazz 矩阵元素的类型
         * @return 转换成数据矩阵
         */
        public <T> T[][] toArray(final Class<T> clazz){
            return this.data.toArray2(clazz);
        }
        
        /**
         * 转换成数据矩阵
         * @return 转换成数据矩阵
         */
        public <U> U toArray(final Function<Double[][],U> mapper){
            return mapper.apply(this.data.toArray2(Double.class));
        }
        
        /**
         * 构造一个数据管道:rec->rec
         * @return 数据处理管道
         */
        public Pipe<IRecord,IRecord> pipe() {
            return Pipe.PIPE(this.data);
        }
        
        /**
         * 构造一个数据管道:dd->dd
         * @return 数据处理管道
         */
        public Pipe<Double[][],Double[][]> pipe2() {
            return Pipe.PIPE(this.toArray());
        }
        
        /**
         * 函数计算
         * @param <U> 结果类型
         * @param evaluator 计算函数
         * @return 函数计算
         */
        public <U> U eval(final Function<IRecord,U> evaluator) {
            return this.pipe().bind(evaluator).evaluate();
        }
        
        /**
         * 提取列名
         * @param index 列名索引从0开始
         * @return 提取列名,如果 size小于等于0，返回null
         */
        public String name(int index) {
            final var sz = this.size();
            if(sz<=0)return null;
            return this.names().get(index%sz);
        }
        
        /**
         * 列名列表 <br>
         * 当 data为null返回一个空列表[]
         * @return 列名列表
         */
        public List<String> names() {
            return this.data == null? new ArrayList<>(): this.data.keys();
        }
        
        /**
         * 创建dataframe
         * @param evaluator 计算函数:rec->rec
         * @return DFrame的
         */
        public DFrame dataframe2(final Function<IRecord,IRecord> evaluator) {
            return this.eval(evaluator).mutate(DFrame::new);
        }
        
        /**
         * 创建dataframe
         * @param evaluator 计算函数:rec->[rec]
         * @return DFrame的
         */
        public DFrame dataframe(final Function<IRecord,Stream<IRecord>> evaluator) {
            return IRecord.ROWS2COLS(this.eval(evaluator)).mutate(DFrame::new);
        }
        
        /**
         * 数据归集 collectR的别名
         * @param <R> 归集结果类型
         * @param collector 数据归集器
         * @return 归集结果
         */
        public <R> R collect(Collector<? super IRecord,?,R> collector) {
            return this.collectR(collector);
        }

        /**
         * 行数据归集 按照行顺序归集
         * @param <R> 归集结果类型
         * @param collector 数据归集器
         * @return 归集结果
         */
        public <R> R collectR(Collector<? super IRecord,?,R> collector) {
            return this.rowS().collect(collector);
        }

        /**
         * rcollect2 (rcollectR2 的后缀2表示这是一个对KVPair 进行归集的版本） <br>
         * 行数据归集 按照行顺序归集
         * @param <R> 归集结果类型
         * @param collector 数据归集器
         * @return 归集结果
         */
        public <R> R rcollect2(final Collector<KVPair<String,?>,List<KVPair<String,Object>>,R> collector) {
            return this.rcollectR2(collector);
        }
        
        /**
         * rcollectR2 (rcollectR2 的后缀2表示这是一个对KVPair 进行归集的版本） <br>
         * 行数据归集 按照行顺序归集
         * @param <R> 归集结果类型
         * @param collector 数据归集器
         * @return 归集结果
         */
        public <R> R rcollectR2(final Collector<KVPair<String,?>,List<KVPair<String,Object>>,R> collector) {
            return this.eval(rec->rec.rcollect2(collector));
        }
        
        /**
         * 数据归集 按照列顺序归集
         * @param <R> 归集结果类型
         * @param collector 数据归集器
         * @return 归集结果
         */
        public <R> R collectC(Collector<? super IRecord,?,R> collector) {
            return this.rowS().collect(collector);
        }

        /**
         * 返回行数据
         * @return 行数据,IRecord 被视作一个 行记录结构
         */
        public List<IRecord> rowL() {
            return this.eval(IRecord::rows2).collect(Collectors.toList());
        }
        
        /**
         * 返回行数据
         * @return 行数据,IRecord 被视作一个 行记录结构
         */
        public Stream<IRecord> rowS() {
            return this.eval(IRecord::rows2);
        }

        /**
         * 返回行数据
         * @param <T> 结果元素类型
         * @param mapper 映射函数 rec->t
         * @return 行数据,IRecord 被视作一个 行记录结构
         */
        public <T> Stream<T> rowS(final Function<IRecord,T> mapper) {
            return this.eval(IRecord::rows2).map(mapper);
        }
        
        /**
         * 返回列数据
         * @return 列数据,IRecord 被视作一个 列表结构,每个key表示行号 从0开始,value 表示数据内容
         */
        public List<IRecord> columnL() {
            return this.eval(IRecord::columns2).collect(Collectors.toList());
        }
        
        /**
         * 返回列数据
         * @return 列数据,IRecord 被视作一个 列表结构,每个key表示行号 从0开始,value 表示数据内容
         */
        public Stream<IRecord> columnS() {
            return this.eval(IRecord::columns2);
        }
        
        /**
         * 返回列数据
         * @return 列数据
         */
        public Stream<FVec<Object>> colS() {
            return this.eval(rec->rec.columns().stream().map(FVec::new));
        }
        
        /**
         * 返回列数据
         * 
         * @return 列数据
         */
        public Stream<NVec> colNS() {
            return this.colS().map(e -> e.isNumberic() 
                ? NVec.of((Number[]) e.originals().data()) 
                : NVec.of(new Double[] {}));
        }
        
        /**
         * 返回列数据
         * @return 列数据
         */
        public List<FVec<Object>> colL() {
            return this.colS().collect(Collectors.toList());
        }
        
        /**
         * 返回列数据
         * @return 列数据
         */
        public List<NVec> colNL() {
            return this.colS().collect(Collectors.toList());
        }
        
        /**
         * 键名 过滤
         * @param idxes 列索引序列
         * @return DFrame
         */
        public DFrame filter(final NVec idxes) {
            return this.filter((Object[])idxes.intA());
        }
        
        /**
         * 键名 过滤
         * @param rng 索引范围
         * @return DFrame
         */
        public DFrame filter(final Range rng) {
            return this.filter(NVec.of(rng));
        }
        
        /**
         * 列选择(过滤)
         * @param idxes 列索引序列，从0开始
         * @return DFrame
         */
        public DFrame filter(final int[] idxes) {
            return this.filter(NVec.of(idxes).intA());
        }
        
        /**
         * 列选择(过滤)
         * @param <T> 参数数组元素类型
         * @param keyidxes 列名或者列索引序列
         * @return DFrame
         */
        @SafeVarargs
        public final <T> DFrame filter(final T ... keyidxes) {
            
            return new DFrame(DFrame.adjustData(data, keyidxes));
        }

        /**
         * row filter <br>
         * 创建dataframe <br>
         * @param row_filter 行过滤函数:rec->boolean
         * @return DFrame 过滤后的结果
         */
        public DFrame rfilter(final Predicate<IRecord> row_filter) {
            return this.eval(rec->rec.rows2().filter(row_filter)
                    .collect(llclc(recs->IRecord.ROWS2COLS(recs).mutate(DFrame::new))));
        }
        
        /**
         * row filter <br>
         * 创建dataframe <br>
         * @param row_filter 行过滤函数: (i:行号索引从0开始,rec:行记录)->boolean
         * @return DFrame 过滤后的结果
         */
        public DFrame rfilter(final BiPredicate<Integer,IRecord> row_filter) {
            final var al = new AtomicInteger(0);
            return this.eval(rec->rec.rows2().filter(r->row_filter.test(al.getAndIncrement(), r))
                    .collect(llclc(recs->IRecord.ROWS2COLS(recs).mutate(DFrame::new))));
        }
        
        /**
         * row filter <br>
         * 创建dataframe <br>
         * @param bb 行指定标记向量 true 选择,false 不选择
         * @return DFrame
         */
        public DFrame rfilter(final Boolean [] bb) {
            return this.rfilter((i,r)->bb[i]);
        }

        /**
         * 提取前n行数据
         * @param n 行数
         * @return DFrame
         */
        public DFrame head(final int n) {
            return this.rowS().limit(n).collect(llclc(recs->IRecord.ROWS2COLS(recs).mutate(DFrame::new)));
        }
        
        /**
         * 提取后n行数据
         * @param n 行数
         * @return DFrame
         */
        public DFrame tail(final int n) {
            final var nrow = this.shape()._1();
            return this.rfilter((i,r)->i>=(nrow-n));
        }
        
        /**
         * 提取指定行号索引中的行数据
         * @param indexes 行号索引向量,行号索引从0开始
         * @return DFrame
         */
        public DFrame rgets(final Integer ...indexes) {
            final var nrow = this.shape()._1();
            final var bb = IRecord.flagbools(false, indexes).apply(nrow);
            return this.rfilter((i,r)->bb[i]);
        }
        
        /**
         * 提取指定行号索引中的行数据
         * @param indexes 行号索引向量,行号索引从0开始
         * @return DFrame
         */
        public DFrame rgets(final NVec indexes) {
            return this.rgets(indexes.intA());
        }
        
        /**
         * 提取指定行号索引范围中的行数据
         * @param rng 行号索引数据范围,行号索引从0开始
         * @return DFrame
         */
        public DFrame rgets(final Range rng) {
            return this.rgets(NVec.of(rng));
        }
        
        /**
         * 转换成一个PVec对象
         * @param splitter 行拆分器:rec->(rec0,rec1)
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord,IRecord> split(Function<IRecord, BasePair<IRecord,IRecord>> splitter){
            return this.rowS(splitter).collect(PVec.pvec2clc());
        }
        
        /**
         * 转换成一个PVec对象
         * @param aa 第一位置字段索引集合,从0开始
         * @param bb 第二位置字段索引集合,从0开始
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord,IRecord> split(Integer[] aa, Integer[] bb){
            return this.split(rec-> BasePair.BP(rec.filter(aa), rec.filter(bb)));
        }
        
        /**
         * 转换成一个PVec对象
         * @param nvec0 第一位置字段索引集合,从0开始
         * @param nvec1 第二位置字段索引集合,从0开始
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord,IRecord> split(NVec nvec0, NVec nvec1){
            return this.split(nvec0.intA(),nvec1.intA());
        }
        
        /**
         * 转换成一个PVec对象
         * @param rng0 第一位置字段索引范围,从0开始
         * @param rng1 第二位置字段索引范围,从0开始
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord,IRecord> split(final Range rng0, final Range rng1){
            return this.split(NVec.of(rng0),NVec.of(rng1));
        }
        
        /**
         * 转换成一个PVec对象
         * @param kk 第一位置字段名称序列
         * @param vv 第二位置字段名称序列
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord,IRecord> split(final String[] kk, final String[] vv){
            return this.split(rec-> BasePair.BP(rec.filter(kk), rec.filter(vv)));
        }
        
        /**
         * 转换成一个PVec对象
         * 
         * @param kk 第一位置字段名称序列,字段名用逗号分隔
         * @param vv 第二位置字段名称序列,字段名用逗号分隔
         * @return PVec&lt;IRecord,IRecord&gt;
         */
        public PVec<IRecord, IRecord> split(final String kk, final String vv) {
            return this.split(rec -> BasePair.BP(rec.filter(kk), rec.filter(vv)));
        }
        
        /**
         * 二元变换:可以改变rec值 (i,rec)->weightable <br>
         * 先为数据指定权重，而后给予重排顺序
         *
         * @param mapper 元素变换器,把rec 变换成一个带有权重的 rec值 : <br>
         *               (i:索引序号从0开始,rec:行数据) -> weightable&lt;t&gt;
         * @return DFrame 的对象实例
         */
        public DFrame shuffle(final BiFunction<Integer, IRecord, Number> mapper) {
            final var ai = new AtomicInteger(0);
            final Function<IRecord, Number> weighter = (rec) -> mapper.apply(ai.getAndIncrement(), rec);
            return this.dataframe(rec -> rec.rows2().map(Weightable.weightf(weighter)).sorted().map(Weightable::value));
        }

        /**
         * 一元权重:只计算权重不改变行rec值,rec->wt <br>
         * 先为数据指定权重，而后给予重排顺序
         *
         * @param weighter 排序的向量的权重函数 rec->num <br>
         *                 即把 行rec映射成一个可以进行比较的数值权重(weight)而后按照weight进行排序：从小打到大
         * @return DFrame 的对象实例
         */
        public DFrame shuffle(final Function<IRecord, Number> weighter) {
            return this.shuffle((i, rec) -> weighter.apply(rec));
        }

        /**
         * 数据随机权重,而后给予行重排顺序
         * 
         * @return DFrame 的对象实例
         */
        public DFrame shuffle() {
            return this.shuffle((i, rec) -> Math.random());
        }
        
        /**
         * 返回列数据 colS的别名
         * @return 列数据
         */
        public Stream<FVec<Object>> fvecS() {
            return this.colS();
        }
        
        /**
         * 返回列数据 colL的别名
         * @return 列数据
         */
        public List<FVec<Object>> fvecL() {
            return this.colL();
        }

        /**
         * 列数目
         * @return 列数目,如果data为null返回0
         */
        public int size() {
            if (this.data == null)
                return 0;
            else
                return this.data.size();
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 术语来源 pandas<br>
         * 返回矩阵形状<br>
         * @return (height,width)的二维矩阵,当this.data 为null的时候,返回(0,0)
         */
        public Tuple2<Integer,Integer> shape() {
            if (this.data == null)
                return Tuple2.TUP2(0, 0);
            else
                return this.data.shape();
        }
        
        /**
         * 行绑定
         * 
         * @param df 另一个数据框
         * @return 一个新生成的数据框
         */
        public DFrame rbind(final DFrame df) {
            final var rec = this.data.duplicate();
            final var keys = Stream.concat(this.names().stream(), df.names().stream()).distinct()
                    .toArray(String[]::new);// 提取键名
            final var nrows = rec.shape()._1(); // rec 的行数量
            for (var k : keys) {
                final var alist = rec.lla(k, Object.class); // alist
                final var blist = df.eval(r -> r.lla(k, Object.class));// blist
                final var list = new ArrayList<Object>( alist == null 
                        ? Range.of(nrows).map(e -> null).collect(Collectors.toList()) // 补填一系列空值
                        : alist);
                if (blist != null)
                    list.addAll(blist);
                rec.add(k, list);
            }
            return new DFrame(rec);
        }
        
        /**
         * 行绑定
         * @param rec 另一个数据框
         * @return 一个新生成的数据框
         */
        public DFrame rbind(final IRecord rec) {
            return this.rbind(new DFrame(rec));
        }
        
        /**
         * 行绑定
         * @param kvs 键,值序列:key0,value0,key1,value1,....
         */
        public DFrame rbind(final Object ... kvs ) {
            return this.rbind(new DFrame(kvs));
        }
        
        /**
         * 列绑定(只添加不同名的列,同名列保持原列不变)
         * 
         * @param df 另一个数据框
         * @return 一个新生成的数据框
         */
        public DFrame cbind(final DFrame df) {
            final var rec = this.data.duplicate(); // 返回结果
            final var kk = this.names(); // 当前的键名序列
            final var keys = df.names().stream().filter(e -> !kk.contains(e)).toArray(String[]::new);// 提取键名
            final var nrows = rec.shape()._1();// 返回结果的行数量
            for (var k : keys) {
                final var klist = df.eval(r -> r.lla(k, Object.class));// 提取k列表
                final var krows = klist.size(); // df的行数
                final var blist = Range.of(nrows).map(i -> klist.get(i.intValue() % krows))
                        .collect(Collectors.toList());
                rec.add(k, krows > 0 ? blist : klist);
            }

            return new DFrame(rec);
        }
        
        /**
         * 列绑定(只添加不同名的列,同名列保持原列不变)
         * @param rec 另一个数据框
         * @return 一个新生成的数据框
         */
        public DFrame cbind(final IRecord rec) {
            return this.cbind(new DFrame(rec));
        }
        
        /**
         * 列绑定(只添加不同名的列,同名列保持原列不变)
         * @param kvs 键,值序列:key0,value0,key1,value1,....
         */
        public DFrame cbind(final Object ... kvs ) {
            return this.cbind(new DFrame(kvs));
        }

        /**
         * 数据精度
         *
         * @param n 数据精度，即显示几为小数
         */
        public String toString(int n) {
            final var tt = this.data.aov2rec(v -> {
                if (v instanceof TVec) return ((TVec<?, ?>) v).data(); // 转换 TVec 类型数据为数组类型
                else return v;
            });
            return tt.toString2(LittleTree.frt(n));
        }
        
        /**
         * 数据精度为4的数据格式化
         */
        public String toString() {
            return this.toString(4);
        }
        
        /**
         * 以行列表的 形式构建数据框
         * @param rows, 行数据,以行列表的 形式构建数据框
         */
        public static DFrame ofrows(final Collection<IRecord> rows) {
            return ofrows(rows.stream());
        }
        
        /**
         * 以行列表的 形式构建数据框
         * @param rows, 行数据,以行列表的 形式构建数据框
         */
        public static DFrame ofrows(final IRecord ... rows) {
            return ofrows(Arrays.stream(rows));
        }
        
        /**
         * 以行列表的 形式构建数据框
         * @param rows, 行数据,以行列表的 形式构建数据框
         */
        public static DFrame ofrows(Stream<IRecord> rows) {
            return rows.collect(DFrame.dfmclc);
        }

        /**
         * 构造实例函数:（不调整数据)
         * @param kvs oo 键,值序列:key0,col0,key1,col1,....
         */
        public static DFrame of(final Object ... kvs) {
            return new DFrame(kvs);
        }

        /**
         * 构造实例函数:（不调整数据)
         * @param data DataFrame 结构的数据结构，每个value都是一个List<String>
         */
        public static DFrame of(final IRecord data) {
            return new DFrame(data);
        }

        /**
         * 构造实例函数
         * @param data DataFrame 结构的数据结构，每个value都是一个List<String>
         * @param b 是否调整data数据,true调整,false 不调整
         */
        public static DFrame of(final IRecord data, final boolean b){
            return new DFrame(data,b);
        }

        /**
         * 对 data 按照 keyidxes 索引进行调整
         * 
         * @param <T> 参数数组元素类型
         * @param data 数据调整
         * @param keyidxes 列名或者列索引序列
         * @return IRecord 调整收的数据
         */
        @SafeVarargs
        public static <T> IRecord adjustData(final IRecord data,final T ... keyidxes) {
            final var keys = keyidxes == null ? data.keys().toArray(String[]::new):keyidxes;
            String[] flds = null;
            if(keys instanceof String[]) {
                flds = (String[])keys;
            }else if(keys instanceof Number[]){
                flds = Arrays.stream((Number[])keys).map(Number::intValue).map(data::idx2key).toArray(String[]::new);
            }else {
                return null;
            }// if
            
            final var rec = Arrays.stream(flds).map(s->data.get(s,numerialize)).map(NVec::data).collect(IRecord.llclc(IRecord::L2REC));
            final var new_keys = new ArrayList<String>(); // 调整键名
            final var mm = new HashMap<String,Integer>();
            for(final var fld:flds) {
                final var id = mm.compute(fld, (k,v)->v==null?0:v+1);
                new_keys.add(id==0?fld:fld+""+id);
            }
            
            return rec.keys(new_keys);
        }
        
        /**
         * 构造函数
         */
        public static DFrame DF(final IRecord data) {
            return new DFrame(data);
        }
        
        /**
         * 把一个T 类型转换成 一个 U类型，如果转换失败 采用默认值 default_value
         * @param <T> T 类型 源类型
         * @param <U> U 类型 目标类型
         * @param default_value 默认值
         * @return t->u 的函数
         */
        @SuppressWarnings("unchecked")
        public static <T, U> Function<T, U> t2u(final U default_value) {
            return t -> {
                if (t == null) {
                    return (U) null;
                } else {
                    if (default_value == null)
                        return (U) null;
                    else {
                        return (default_value.getClass().isAssignableFrom(t.getClass())) ? (U) t : default_value;
                    }
                }
            };
        }

        /**
         * 把一个对象转换成一个数据元素的流
         * @param obj 待转换的数据对象
         * @return 数据元素的流
         */
        @SuppressWarnings("unchecked")
        public static Stream<Object> obj2stream(final Object obj){
            if(obj instanceof Collection) {// 集合类型
                return ((Collection<Object>)obj).stream();
            }else if(obj instanceof Object[]) { // 对象数组类型
                return Arrays.stream((Object[])obj);
            }else if(obj instanceof TVec) { // TVec类型
                return ((TVec<Object,?>)obj).stream();
            }else if(obj instanceof IRecord){// IRecord 类型
                return ((IRecord)obj).values().stream();
            }else if(obj instanceof Stream){// I流类型
                return (Stream<Object>)obj;
            }else if(obj instanceof Map){// Map 类型
                return ((Map<Object,Object>)obj).values().stream();
            }else{// 其他类型
                return Stream.of(obj);
            }
        }

        /**
         * KVPair 转 BasePair
         *
         * @param kvp  KVPair 对象
         * @param <K> 键类型
         * @param <V> 值类型
         * @return BasePair 对象
         */
        public static <K, V> BasePair<K, V> kvp2bp(final KVPair<K, V> kvp) {
            return BasePair.bp(kvp.key(), kvp.value());
        }

        /**
         * BasePair 转 KVPair
         *
         * @param bp  BasePair 对象
         * @param <K> 键类型
         * @param <V> 值类型
         * @return KVPair 对象
         */
        public static <K, V> KVPair<K, V> bp2kvp(final BasePair<K, V> bp) {
            return KVPair.KVP(bp.key(), bp.value());
        }

        /**
         * BasePair 转 KVPair
         *
         * @param mapper  BasePair 的键名变换器 k->t
         * @param <> 键名变换结果类型
         * @param <K> 键类型
         * @param <V> 值类型
         * @return KVPair 对象
         */
        public static <T,K, V>  Function<BasePair<K,V>,KVPair<T, V>> bp2kvpf1(final Function<K,T> mapper) {
            return bp->KVPair.KVP(mapper.apply(bp.key()), bp.value());
        }

        /**
         * BasePair 转 KVPair
         *
         * @param mapper  BasePair 值变换器 v->u
         * @param <K> 键类型
         * @param <V> 值类型
         * @param <U> 值变换结果类型
         * @return KVPair 对象
         */
        public static <K, V,U>  Function<BasePair<K,V>,KVPair<K, U>> bp2kvpf2(final Function<V,U> mapper) {
            return bp->KVPair.KVP(bp.key(), mapper.apply(bp.value()));
        }

        /**
         * KVPair 转 BasePair
         *
         * @param mapper  BasePair 的键名变换器 k->t
         * @param <T> 键名变换结果类型
         * @param <K> 键类型
         * @param <V> 值类型
         * @return BasePair 对象
         */
        public static <T,K, V>  Function<KVPair<K,V>,BasePair<T, V>> kvp2bpf1(final Function<K,T> mapper) {
            return kvp->BasePair.bp(mapper.apply(kvp.key()), kvp.value());
        }

        /**
         * KVPair 转 BasePair
         *
         * @param mapper  BasePair 值变换器 v->u
         * @param <K> 键类型
         * @param <V> 值类型
         * @param <U> 值变换结果类型
         * @return BasePair 对象
         */
        public static <K, V,U>  Function<KVPair<K,V>,BasePair<K, U>> kvp2bpf2(final Function<V,U> mapper) {
            return kvp->BasePair.bp(kvp.key(), mapper.apply(kvp.value()));
        }
        
        /**
         * 数值化管道
         */
        public final static Function<Object, NVec> numerialize = DUMMY(Object.class)
                .bind(DFrame::obj2stream)
                .bind(stream -> stream.map(IRecord.coerce(Double.class)).toArray(Double[]::new)).bind(NVec::of)
                .functionalize(); // 把List<String>转换成NVec的函数

        /**
         * 因子化管道
         */
        public final static Function<Object, FVec<Object>> factorize = DUMMY(Object.class)
                .bind(DFrame::obj2stream)
                .bind(ss -> ss.map(e -> e).toArray(Object[]::new))
                .bind(FVec::new).functionalize(); // 把List<String>转换成FVec的函数

        /**
         * DataFrame 归集器 [rec]->DFrame
         */
        public static Collector<IRecord, List<IRecord>, DFrame> dfmclc = IRecord.r2uclc(DFrame::new);
        
        private final IRecord data; // 源数据
    }
    
    /**
     *  因子向量
     * @author gbench
     *
     */
    public static class FVec<T> extends NVec{
        
        /**
         * 构造一个 因子向量
         * @param vv 对象数组
         */
        @SafeVarargs
        public FVec(final T... vv) {
            super(new Double[vv.length]);
            this.factors = factorize(vv);
            for(int i=0;i<vv.length;i++) this.data[i]=this.factors.get(vv[i]);
        }
        
        /**
         * 构造一个 因子向量
         * @param vv 对象数据流
         */
        public FVec(final Collection<T> vv) {
            this(vv.stream());
        }
        
        /**
         * 构造一个 因子向量
         * @param vv 对象数据列表
         */
        public FVec(final Stream<T> vv) {
            this((T[])vv.collect(IRecord.aaclc(e->e)));
        }
        
        /**
         * 获取原向量
         * @return 原向量
         */
        public XVec<T> originals(){
            return this.fmap(this::original);
        }
        
        /**
         * 因子的原数据
         * @param factor 因子
         * @return 因子的原数据
         */
        public T original(final Double factor){
            return this.getOriginalMap().get(factor);
        }
        
        /***
         * 是否为数值限量
         * @return true 是数字类型,false 非数字类型
         */
        public boolean isNumberic(){
            final var v = this.getOriginalMap().values().iterator().next();
            return v instanceof Number;
        }
        
        /**
         * 获取原象集合
         * 
         * @return 原象集合
         */
        public Map<Double, T> getOriginalMap() {
            if (originalMap == null) {
                originalMap = new HashMap<>();
                this.factors.forEach((k, v) -> originalMap.put(v, k));
            }// 制造原象
            return originalMap;
        }
        
        /**
         * 生成一个 FVec
         * @param <T> 数据对象向量类型
         * @param vv 对象数组
         * @return FVec
         */
        @SafeVarargs
        public static <T> FVec<T> of(final T... vv) {
            return new FVec<>(vv);
        }
        
        /**
         * 因子向量
         * @param <T> 原向量的元素类型
         * @param vv 原向量的数据数组
         * @return 向量的因子
         */
        public static <T> Map<T,Double> factorize(final T[] vv){
            final var factors = new HashMap<T,Double>();
            final var al = new AtomicLong(0);
            for(var v:vv) factors.computeIfAbsent(v, t->(double)al.getAndIncrement());
            return factors;
        }

        private final Map<T,Double> factors; // 数据因子
        private transient Map<Double,T> originalMap=null; // 数据原数据映射
    }
    
    public static final String DELIM = "[\\s,]+"; // 可以通过修改DELIM来实现数据分隔模式的修改。

}